#pragma once

#include <vector>
#include "Settings.h"
#include "SampleMarker.h"

class VocoderImpl;
class Overlapper;

/*
VocoderListener and VocoderListenerImpl receive notifications from Modulator, Carrier and Vocoder when new samples are processed.
This can be useful for e.g. recording the samples.
Implementors must make their own copies of incoming data as it may be deleted or overwritten after calls to the Notify methods.
*/
class VocoderListener
{
public:
	VocoderListener(){}
	virtual ~VocoderListener(){}

	/*
	Modulator should call this listener when NextModulatorSample is called
	*/
	virtual void NotifyModulatorSample(short* sample, unsigned int length) = 0;

	/*
	Carrier should call this listener when CreateCarrierSample is called
	*/
	virtual void NotifyCarrierSample(short* sample, unsigned int length) = 0;

	/*
	Vocoder should call this listener each time it has vocoded a sample
	*/
	virtual void NotifyVocoderSample(short* sample, unsigned int length) = 0;
};

/*
VocoderListener implementation that stores the samples it's notified about in its public accessible vectors.
*/
class VocoderListenerImpl : public VocoderListener
{
public:
	volatile bool isListening;

	VocoderListenerImpl(){isListening=true;}
	~VocoderListenerImpl(){}

	virtual void NotifyModulatorSample(short* sample, unsigned int length);
	virtual void NotifyCarrierSample(short* sample, unsigned int length);
	virtual void NotifyVocoderSample(short* sample, unsigned int length);
	
	std::vector<short> modulatorSamples;
	std::vector<short> carrierSamples;
	std::vector<short> vocoderSamples;

	
};


/*
Provides frequency from a given sample.
May put markers on the sample, Voiced/Unvoiced.
*/
class FrequencyProvider
{
public:
	FrequencyProvider(void){}
	virtual ~FrequencyProvider(void){}

	/*
	Returns the frequency associated with the current sample
	*/
	virtual unsigned int GetFrequency(short* sample, unsigned int length, std::vector<SampleMarker>* markers) = 0;
};

/*
Creates audio samples corresponding to incoming modulator sample.
*/
class Carrier
{
public:
	Carrier(void){}
	virtual ~Carrier(void){}

	/*
	Runs StopConsonantAnalyzer and copies modulatorSample as its own output when stop consonants are found.
	*/
	virtual void ApplyStopConsonants(short* modulatorSample, short* outputSample, unsigned int length, std::vector<SampleMarker>* markers);

	/*
	Sets the current frequency provider. 
	If the carrier creates the frequency of its output realtime, it should use frequencies provided by the FrequencyProvider.
	*/
	virtual void SetFrequencyProvider(FrequencyProvider* frequencyProvider) = 0;

	/*
	Carrier implementor must create a short* of same length as modulatorSample.
	Deletion of the sample is up to the Carrier (caller should make a copy if needed).
	*/
	virtual short* CreateCarrierSample(Settings* settings, short* modulatorSample, unsigned int length, std::vector<SampleMarker>* markers) = 0;
};

/*
Provides voice samples as requested by a vocoding loop.
This can be e.g. from a speech generator or file.
*/
class Modulator
{
public:
	Modulator(void){}
	virtual ~Modulator(void){}

	/*
	Fill output with the next part of the modulator's sample
	If the modulator has reached its input stream's end, it should fill the rest of the output with zeros (silence) and return false.
	Otherwise, if output is fully populated, return true.
	*/
	virtual bool NextModulatorSample(short* output, unsigned int length, std::vector<SampleMarker>* markersReceiver) = 0;
};

/*
Vocodes incoming samples and sends the output to its audioReceiver and/or receiving output buffer
*/
class Vocoder
{
public:
	Vocoder(void);
	~Vocoder(void);

	/*
	Initialized the vocoder.
	carrier - mandatory if CreateCarrierSampleAndVocode method is used.
	settingsProvider - mandatory, settings will always be updated before vocoding each window
	vocoderListener - optional, receives NotifyModulatorSample and NotifyVocoderSample when either CreateCarrierSampleAndVocode or Vocode is called.
	overlapper - optional, handles window overlapping if that is chosen. Should be used with OverlappingCarrier and OverlappingModulator.
	*/
	void Initialize(Carrier* carrier, SettingsProvider* settingsProvider, VocoderListener* vocoderListener, Overlapper* overlapper);
	Settings* GetSettings();

	/*
	Vocodes modulator and carrier.
	If output!=NULL, then the output is written into this buffer
	If audioReceiver!=NULL then it gets a callback with the current output.
	
	As vocoder may have overlapping facilities, length may be shorter than specified in input.
	The actual vocoded length is returned.
	*/
	int Vocode(short* modulator, short* carrier, short* output, unsigned int length);

private:
	Settings settings;

	Carrier* carrier;
	SettingsProvider* settingsProvider;
	VocoderListener* vocoderListener;
	VocoderImpl* vocoder;
	Overlapper* overlapper;

	void UpdateSettings();
};